#include "kernel/apic/ipi.h"
#include "kernel/log/log.h"
#include "kernel/apic/apic.h"
#include "libs/msr.h"
#include "libs/lib.h"
#include "kernel/memory/memory.h"
#include "kernel/task/task.h"

IpiHandler::IpiHandler(uint64_t number/* args */):
interrupthandler(number,INTERRUPTMANAGER)
{
    
}

IpiHandler::~IpiHandler()
{


}
StackFrame* IpiHandler::handleInterrupt(StackFrame* fs)
{

    LOG_ERROR("cpuid:%d IPI INFO:%x\n",getAPICID(),interruptNum);

}


IpiHpetHandler::IpiHpetHandler(uint64_t number/* args */):
IpiHandler(number)
{
}

IpiHpetHandler::~IpiHpetHandler()
{
}


StackFrame* IpiHpetHandler::handleInterrupt(StackFrame* fs){

    uint64_t cpuid = getAPICID();

    if(TASKMANAGER->schedules[cpuid]->cpuExecTaskJiffies <= 0){

            current->flags |=NEED_SCHEDULE;

    }

    if(INTERRUPTMANAGER->taskManagerHaveFinish){
    
        switch(current->priority){

        case 0:
        case 1:
            TASKMANAGER->schedules[cpuid]->cpuExecTaskJiffies--;
                current->vrunTime += 1;
                break;
        case 2:
        default:
            TASKMANAGER->schedules[cpuid]->cpuExecTaskJiffies-=2;
                current->vrunTime += 2;
                break;
        }
            


    }


}




IpiScheduleHnalder::IpiScheduleHnalder(uint64_t number/* args */):
IpiHandler(number)
{
}

IpiScheduleHnalder::~IpiScheduleHnalder()
{


}

StackFrame* IpiScheduleHnalder::handleInterrupt(StackFrame* fs){

    
    
    task* ta = get_current();
    
    if(ta->flags & NEED_SCHEDULE){
    
        TASKMANAGER->shcedule();
    
    }

}






IpiManager* IpiManager::ipim = 0;

IpiManager::IpiManager(/* args */)
{


    ipim = this;
    hpetHandler = new IpiScheduleHnalder(IPISCHEDULE_VECTOR);
    scheduleHandler = new IpiHpetHandler(IPIHPET_VECTOR);


}

IpiManager::~IpiManager()
{
}

void IpiManager::sendIpi(uint64_t cpuId,uint64_t vector){

    


    INT_CMD_REG icr_entry;
    icr_entry.vector = vector;
    icr_entry.deliver_mode = APIC_ICR_IOAPIC_Fixed;
	icr_entry.dest_mode = ICR_IOAPIC_DELV_PHYSICAL;
	icr_entry.deliver_status = APIC_ICR_IOAPIC_Idle;
	icr_entry.res_1 = 0;
	icr_entry.level = ICR_LEVEL_DE_ASSERT;
	icr_entry.trigger = APIC_ICR_IOAPIC_Edge;
	icr_entry.res_2 = 0;
	icr_entry.dest_shorthand = ICR_No_Shorthand;
	icr_entry.res_3 = 0;
    icr_entry.destination.x2apic_destination = cpuId;
    wrmsr(IA32_APIC_ICR,*(uint64_t*)&icr_entry);



}


